﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace WpfPractice.MVVM
{
    public class RelayCommand : ICommand
    {
        // 定义一个Action类型的委托，用于执行命令
        private readonly Action<object> _execute;
        // 定义一个Func<object, bool>类型的委托，用于判断命令是否可执行
        private readonly Func<object, bool> _canExecute;
        // public delegate void EventHandler(object? sender, EventArgs e);
        public event EventHandler CanExecuteChanged
        {
            //普通事件的add和remove访问器只用于管理私有委托类型的订阅者列表，确保+=和-=操作符的正确行为
            //这里的写法是为ICommand特殊设计的,不仅将事件处理方法注册到你的事件中，
            //同时还将该处理方法注册到CommandManager.RequerySuggested事件中
            /*
             * 将此事件的add和remove访问器直接关联到CommandManager.RequerySuggested事件，实现了命令状态的自动更新。
             * 这意味着当命令的可执行状态可能发生变化时（例如，用户的操作使得命令的可执行状态改变），
             * CommandManager会触发RequerySuggested事件，从而间接触发CanExecuteChanged事件，
             * 通知界面元素更新相应命令的状态
             */
            add { CommandManager.RequerySuggested += value; }
            /*
             * CanExecuteChanged事件与CommandManager.RequerySuggested事件挂钩，主要是为了利用WPF提供的自动化命令状态更新机制
             * ，从而简化命令的可执行状态管理.如果没有自动的状态更新机制，开发者就需要手动触发命令的CanExecuteChanged事件，
             * 以更新命令的可执行状态
             */
            remove { CommandManager.RequerySuggested -= value; }
        }

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            _execute = execute;// 保存命令执行逻辑的委托
            _canExecute = canExecute;// 保存判断命令可执行性的委托
        }

        // 实现ICommand接口的CanExecute方法,该方法用于判断命令是否可执行，由界面元素调用
        // 如果没有提供判断逻辑（_canExecute为null），则命令默认为可执行状态
        public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);

        // 实现ICommand接口的Execute方法,该方法用于执行命令，实际上就是调用_execute委托,由界面元素在命令触发时调用
        public void Execute(object parameter) => _execute(parameter);
    }
}
